package com.biboheart.adapter.support.utils;

import com.biboheart.adapter.model.AdapterConfigModel;
import com.biboheart.adapter.model.SelectionModel;
import com.fasterxml.jackson.core.JsonProcessingException;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class AdapterUtils {
    @SuppressWarnings("unchecked")
    public static AdapterConfigModel stringToModel(String configModelStr) {
        if (null == configModelStr || "".equals(configModelStr)) {
            return null;
        }
        if ('[' == configModelStr.charAt(0)) {
            configModelStr = "{\"name\": null,\"sourceObject\": null,\"sourceName\": null,\"targetName\": null,\"targetClass\": \"map\",\"converter\": null,\"auxiliary\": null,\"contrastSn\": null,\"contrastType\": 1,\"def\": null,\"instructParams\": null,\"remark\": null,\"children\": " + configModelStr + "}";
        }
        Map<String, Object> map;
        try {
            map = JsonUtils.json2objWithType(configModelStr, Map.class);
        } catch (JsonProcessingException e) {
            return null;
        }
        return mapToModel(map);
    }

    @SuppressWarnings("unchecked")
    private static AdapterConfigModel mapToModel(Map<String, Object> map) {
        AdapterConfigModel adapterConfigModel = new AdapterConfigModel();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String name = entry.getKey();
            if (Arrays.asList("children", "selectionModelList").contains(name)) continue;
            Object valObj = entry.getValue();
            if (!"def".equals(name)) {
                setValue(adapterConfigModel, name, valObj);
                continue;
            }
            if (null == valObj) continue;
            AdapterConfigModel defConfigModel = null;
            if (valObj instanceof String) {
                defConfigModel = new AdapterConfigModel();
                defConfigModel.setAuxiliary(valObj);
            } else if (valObj instanceof Map) {
                defConfigModel = mapToModel(ObjectTypeUtils.convertType(valObj, Map.class));
            }
            adapterConfigModel.setDef(defConfigModel);
        }
        Object selectionModelObj = map.get("selectionModelList");
        if (null != selectionModelObj) {
            List<Map<String, Object>> mapList = ObjectTypeUtils.convertType(selectionModelObj, List.class);
            if (!mapList.isEmpty()) {
                List<SelectionModel> selectionModelList = new ArrayList<>();
                adapterConfigModel.setSelectionModelList(selectionModelList);
                for (Map<String, Object> selectionMap : mapList) {
                    SelectionModel selectionModel = new SelectionModel();
                    Object name = selectionMap.get("name");
                    Object value = selectionMap.get("value");
                    selectionModel.setName(ObjectTypeUtils.convertType(name, String.class));
                    selectionModel.setValue(ObjectTypeUtils.convertType(value, String.class));
                    selectionModelList.add(selectionModel);
                }
            }
        }
        Object childrenObj = map.get("children");
        if (null != childrenObj) {
            List<Map<String, Object>> mapList = ObjectTypeUtils.convertType(childrenObj, List.class);
            if (!mapList.isEmpty()) {
                List<AdapterConfigModel> children = new ArrayList<>();
                adapterConfigModel.setChildren(children);
                for (Map<String, Object> childMap : mapList) {
                    children.add(mapToModel(childMap));
                }
            }
        }
        return adapterConfigModel;
    }

    private static void setValue(Object obj, String name, Object val) {
        if (null == obj) {
            return;
        }
        Class<?> clazz = obj.getClass();
        try {
            PropertyDescriptor pd = new PropertyDescriptor(name, clazz);
            Method setMethod = pd.getWriteMethod();//获得set方法
            setMethod.setAccessible(true);
            setMethod.invoke(obj, val);
        } catch (IntrospectionException | IllegalAccessException | InvocationTargetException ignored) {
        }
    }
}
